<?php

	/**
	 * A BoxContentList objektum. Lehet két típusa: fixed meg autoselect. Utóbbi képes
	 * a társított cikkek (box content típus) listájából egy random válogatást készíteni, majd
	 * utána azon mozogni.
	 *  
	 * Képes felépülni a db rekordból, de az aktuális állapotát session-ben tartja.
	 * És ez meg is marad mindaddig, amíg nem érkezik kifejezetten kérés arra, hogy most rendezze
	 * újra magát.
	 * 
	 * A fixed típus picit egyszerűbb, itt nem kell session-ben tartani a cikk-lista random
	 * válogatását - lévén ez fixed, ez tehát nem válogat.
	 * 
	 * Az állapota szintén tartalmazza amúgy, hogy éppen melyik cikken (index) áll a user, így
	 * a "menj előrébb" / "menj hátrébb" műveletek simán értelmezhetőek
	 * 
	 * @author ironhawk
	 *
	 */
	class BoxContentList {
		
		public $id;
		/**
		 * A szülő box-tab objektumunk
		 * @var BoxTab
		 */
		public $parentBoxTab;
		public $name;
		public $type;
		public $manualStep;
		public $autoStep;
		public $isDefault;
		public $sizeMin;
		public $sizeMax;
		/**
		 * ezt örökli a szülőtől
		 * @var string
		 */
		public $langcode;
		
		/**
		 * A cikkek id-i akik ehhez a listához tartoznak
		 * @var array
		 */
		public $articleIds;
		
		/**
		 * Csak autoselect típusnál van igazán értelme, ezen cikkeket választotta ki a listából a cucc.
		 * Az állapota session-ben tárolódik, onnan nyalja fel mindaddig amíg az objektum él
		 * @var array
		 */
		public $selectedArticleIds;
		/**
		 * A $selectedArticleIds tömbben ezen indexű tartalom látszik éppen.
		 * @var int
		 */
		public $currentIndex;
		
		protected $attributes;
		
		
		public function BoxContentList($dbRecord, $_parentTab)
		{
			$this->id = $dbRecord['id'];
			$this->parentBoxTab = $_parentTab;
			$this->langcode = $_parentTab->langcode;
			$this->isDefault = DBUtil::decodeBooleanFieldValue($dbRecord['isdefault']);
			$this->name = $dbRecord['name'];
			if(is_array($dbRecord['box_article_ids']))
			{
				// nem kell csinálni semmit
				$this->articleIds = $dbRecord['box_article_ids'];
			}
			else
			{
				if(!empty($dbRecord['box_article_ids']))
					$this->articleIds = unserialize($dbRecord['box_article_ids']);
				else
					$this->articleIds = array();
			}
			$this->type = $dbRecord['type'];
			$this->manualStep = DBUtil::decodeBooleanFieldValue($dbRecord['manualstep']);
			$this->autoStep = $dbRecord['autostep'];
			
			if($this->type == BOXCONTENTLIST_TYPE_FIXED)
			{
				$this->sizeMin = null;
				$this->sizeMax = null;
			}
			else
			{
				$this->sizeMin = $dbRecord['sizemin'];
				$this->sizeMax = $dbRecord['sizemax'];
			}
			
			if(empty($dbRecord['attributes']))
				$this->attributes = null;
			else
				$this->attributes = unserialize($dbRecord['attributes']);
			
			$this->reloadState();
		}
		
		
		protected function reloadState()
		{
			if(IS_ADMIN_CONTEXT)
				// admin felületen nincs ilyen
				return;
			
			$currentIndex = FunctionLibrary::getSessionValue("bxcl_".$this->langcode."_".$this->id."_cInd", 0);
			if($this->type != BOXCONTENTLIST_TYPE_FIXED)
			{
				$this->selectedArticleIds = FunctionLibrary::getSessionValue("bxcl_".$this->langcode."_".$this->id."_aIds", null);
			}
			
			$this->setIndex($currentIndex);
		}
		
		
		protected function saveState()
		{
			if(IS_ADMIN_CONTEXT)
				// admin felületen nincs ilyen
				return;
			
			$_SESSION["bxcl_".$this->langcode."_".$this->id."_cInd"] = $this->currentIndex;
			if($this->type != BOXCONTENTLIST_TYPE_FIXED)
				$_SESSION["bxcl_".$this->langcode."_".$this->id."_aIds"] = $this->selectedArticleIds;
			
		}
		
		/**
		 * Az index álljon ide! Ha az index nagyobb mint a max, akkor a max lesz.
		 * Ha kisebb 0 akkor 0 lesz. Ha a lista üres, akkor -1-re áll
		 * 
		 * @param $index
		 */
		public function setIndex($index)
		{
			$maxIndex = $this->getMaxIndex();
			if($maxIndex == -1)
			{
				// khm, üres lista van!
				$index = -1;
			}
			else
			{
				if($index < 0)
					$index = 0;
				elseif ($index > $maxIndex)
					$index = $maxIndex;
			}
			
			// van változás?
			// itt óvatosan, mert a 0 érték magától egyenlő lenne a null értékkel!
			if(!is_null($this->currentIndex) && $this->currentIndex == $index)
				return;
				
			$this->currentIndex = $index;
			$this->saveState();
		}
		
		/**
		 * Megmondja hogy ez a lista aktív-e.
		 * @return boolean
		 */
		public function isActive()
		{
			return ($this->parentBoxTab->currentBoxContentListId == $this->id);
		}
		
		/**
		 * Lép a következő cuccra - ha az aktuális index a maximális index akkor nem megy sehova
		 */
		public function nextElement()
		{
			if ($this->currentIndex + 1 == count($this->articleIds)) {
				$this->firstElement();
			} else {
				$this->setIndex($this->currentIndex + 1);
			}
		}

		/**
		 * Lép az előző cuccra
		 */
		public function prevElement()
		{
			if ($this->currentIndex == 0) {
				$this->lastElement();
			} else {
				$this->setIndex($this->currentIndex - 1);
			}
		}
		
		/**
		 * Lép az első cuccra
		 */
		public function firstElement()
		{
			$this->setIndex(0);
		}

		/**
		 * Lép az utolsó cuccra
		 */
		public function lastElement()
		{
			$this->setIndex(count($this->articleIds) - 1);
		}

		/**
		 * Megmondja hogy van-e még következő elem
		 * @return boolean
		 */
		public function hasNextElement()
		{
			return ($this->currentIndex > -1 && $this->getMaxIndex() != $this->currentIndex);
		}

		/**
		 * Megmondja hogy van-e még előző elem
		 * @return boolean
		 */
		public function hasPrevElement()
		{
			return ($this->currentIndex > 0);
		}
		
		/**
		 * A hívás hatására az átadott target súly-halmaz
		 * szerint készít egy sizeMin-sizeMax közötti elemszámú leválogatást a cikkekből.
		 * Majd a currentIndex számláló 0-ra áll.
		 * Végül menti a saját állapotát.
		 */
		public function initArticleList()
		{
			if($this->type != BOXCONTENTLIST_TYPE_FIXED)
			{
				// mennyit?
				$howMany = mt_rand($this->sizeMin, $this->sizeMax);
				if($howMany < 1)
					$howMany = 1;
				
				$notSelectedYet = $this->articleIds;
				$this->selectedArticleIds = array();
				while(count($notSelectedYet) > 0 && count($this->selectedArticleIds) < $howMany)
				{
					$randomIndex = mt_rand(0, count($notSelectedYet) - 1);
					array_push($this->selectedArticleIds, $notSelectedYet[$randomIndex]);
					array_splice($notSelectedYet, $randomIndex, 1);
				}
				
				// ilyenkor muszáj 0-zni az indexet, de csak ilyenkor
				// a fix listák indexe nem mászik el
				
				// az index 0-zása a setIndex-en megy keresztül, mert az felismeri az üres listát is!
				$this->setIndex(0);

				// egy saveState ilyenkor mindenképpen kell, hogy az autoselect lista tuti le legyen mentve!
				$this->saveState();
			}
		}
		
		/**
		 * A cikklistából visszaadja a kívánt indexű elemet vagy null ha nincs olyan index
		 * 
		 * @param $index
		 * @return int a cikk id-je ami azon az indexen van vagy null
		 */
		public function getArticleId($index)
		{
			$articleId = null;
			
			// a negatív index faszság!
			if($index >= 0)
			{
				if($this->type != BOXCONTENTLIST_TYPE_FIXED)
				{
					if(isset($this->selectedArticleIds[$index]))
						$articleId = $this->selectedArticleIds[$index];
				}
				else
				{
					if(isset($this->articleIds[$index]))
						$articleId = $this->articleIds[$index];
				}
			}
			
			return $articleId;
		}
		
		/**
		 * Mi a létező legnagyobb index ami lehet? Ha a lista üres, akkor -1 megy vissza!
		 * 
		 * @return int a max felvehető index vagy -1 ha üres a lista
		 */
		public function getMaxIndex()
		{
			if($this->type != BOXCONTENTLIST_TYPE_FIXED)
				return count($this->selectedArticleIds) - 1;
			else
				return count($this->articleIds) - 1;
		}
		
		/**
		 * HTML generálása.
		 * @return string
		 */
		public function generateHtml()
		{
			$html = "";
			
			$articleId = $this->getArticleId($this->currentIndex);
			if(!is_null($articleId))
			{
				// jó, van cikk id!
				$tpl = BaseSitePage::loadTemplateFile("article_boxcontent.tpl.html");
				TextHandler::insertTextsIntoTemplate($tpl);
				//$tpl = null;
	
				$html = ExtendedArticleHandler::generateArticleHtml(SiteHandler::getCurrentSiteId(), $articleId, $this->langcode, $tpl);
			}

			return $html;
		}
		
		/**
		 * Megmondja h az adott cikk használatban van-e - azaz társítva van-e hozzá...
		 * 
		 * @param $articleId
		 * @return boolean
		 */
		public function isArticleUsed($articleId)
		{
			return FunctionLibrary::arrayContains($this->articleIds, $articleId);
		}

		/**
		 * Visszaad egy fake db record reprezentánst
		 * @return array
		 */
		protected function getFakeDBRecord()
		{
			$fakeDBRecord = array();
			$fakeDBRecord['name'] = $this->name;
			$fakeDBRecord['type'] = $this->type;
			$fakeDBRecord['sizemin'] = $this->sizeMin;
			$fakeDBRecord['box_article_ids'] = $this->articleIds;
			if(empty($this->attributes))
				$fakeDBRecord['attributes'] = null;
			else
				$fakeDBRecord['attributes'] = serialize($this->attributes);

			return $fakeDBRecord;
		}

		/**
		 * Ez egy modellezés. Milyen warning-ok születnének, ha az adott cikket (box content)
		 * törölné a user?
		 * Leellenőrzi az adott objektumot, és egy üzenet-tömbben visszaadja
		 * a bajait.
		 * Ha nincs vele baja, null megy vissza.
		 * 
		 * @return array null ha semmi baja, probléma üzenet-tömb (warningok) ha igen
		 */
		public function checkObjectIfMemberArticleIsDeleted($articleId)
		{
			$fakeDBRecord = $this->getFakeDBRecord();
			// gondolatban törlünk a tömbből
			$fakeArticleIds = FunctionLibrary::arrayRemove($this->articleIds, $articleId);
			$fakeDBRecord['box_article_ids'] = $fakeArticleIds;
			
			// itt lehetünk picit okosabbak név szintjén, mivel meg tudjuk mondani melyik box, melyik
			// tab melyik listája
			$boxAndTab = TextHandler::getParsedText("bxls_box", array("name"=>$this->parentBoxTab->parentBox->name));
			$boxAndTab .= ", " . TextHandler::getParsedText("bxls_boxtab", array("name"=>$this->parentBoxTab->label));
			$boxAndTab = " (".$boxAndTab.")";
			
			return BoxContentList::checkRecord($fakeDBRecord, $boxAndTab);
		}
		
		/**
		 * Leellenőrzi az adott objektumot, és egy üzenet-tömbben visszaadja
		 * a bajait.
		 * Ha nincs vele baja, null megy vissza.
		 * 
		 * @return array null ha semmi baja, probléma üzenet-tömb (warningok) ha igen
		 */
		public function checkObject()
		{
			$fakeDBRecord = $this->getFakeDBRecord();
			// itt lehetünk picit okosabbak név szintjén, mivel meg tudjuk mondani melyik box, melyik
			// tab melyik listája
			$boxAndTab = TextHandler::getParsedText("bxls_box", array("name"=>$this->parentBoxTab->parentBox->name));
			$boxAndTab .= ", " . TextHandler::getParsedText("bxls_boxtab", array("name"=>$this->parentBoxTab->label));
			$boxAndTab = " (".$boxAndTab.")";
			
			return BoxContentList::checkRecord($fakeDBRecord, $boxAndTab);
		}
		
		/**
		 * Leellenőrzi az adott box_content_list rekordot, és egy üzenet-tömbben visszaadja
		 * a bajait.
		 * Ha nincs vele baja, null megy vissza.
		 * 
		 * @param array $dbRecord a db rekord
		 * @param string $boxAndTab opcionálisan adhatsz egy stringet ami leírja melyik box melyik füléről van szó, de lehet null
		 * @return array null ha semmi baja, probléma üzenet-tömb (warningok) ha igen
		 */
		public static function checkRecord($dbRecord, $boxAndTab = null)
		{
			$msgs = array();
			
			if(empty($boxAndTab))
				$boxAndTab = "";
			
			$type = $dbRecord['type'];
			$class = $dbRecord['class'];
			
			if($class == "BoxContentList")
			{
				if($type == BOXCONTENTLIST_TYPE_FIXED)
					$sizeMin = 1;
				else
					$sizeMin = $dbRecord["sizemin"];
	
				if(empty($dbRecord['box_article_ids']))
					$articleIds = array();
				else if (is_array($dbRecord['box_article_ids']))
					$articleIds = $dbRecord['box_article_ids'];
				else
					$articleIds = unserialize($dbRecord['box_article_ids']);
	
				if(count($articleIds) == 0)
				{
					// egyetlen eleme sincsen!
					array_push($msgs, TextHandler::getParsedText("bxls_warn_empty", array("name"=>$dbRecord['name'], "boxAndTab"=>$boxAndTab)));
				}
				elseif(count($articleIds) < $sizeMin)
				{
					// kevesebb elem van benne mint a min size
					array_push($msgs, TextHandler::getParsedText("bxls_warn_lessthanminsize", array("name"=>$dbRecord['name'], "boxAndTab"=>$boxAndTab)));
				}
			}
			/*
			elseif($class == "BrandBoxContentList")
			{
				
			}
			*/
			
			if(count($msgs) == 0)
				return null;
			else
				return $msgs;
		}
		
		/**
		 * Elkészíti a megfelelő objektumot és visszaadja azt.
		 * 
		 * @param array $dbRecord
		 * @param BoxTab $_parentTab
		 * @return BoxContentList
		 */
		public static function createFromDBRecord($dbRecord, $_parentTab)
		{
			if($dbRecord['class'] == "BoxContentList")
				return new BoxContentList($dbRecord, $_parentTab);
				
			/*
			if($dbRecord['class'] == "BrandBoxContentList")
				return new BrandBoxContentList($dbRecord, $_parentTab);

			if($dbRecord['class'] == "CategoryBoxContentList")
				return new CategoryBoxContentList($dbRecord, $_parentTab);
			*/
				
			Log::error("unknown 'class': ".$dbRecord['class']);
			return null;
		}
		
		private function __________attributes(){}
		
		
		/**
		 * Visszaadja az adott attribútumot, vagy ha nincs akkor az adott defValue-t.
		 * 
		 * @param $name
		 * @param $defValue
		 * @return unknown_type
		 */
		public function getAttribute($name, $defValue = null) {
			
			if(empty($this->attributes))
				return $defValue;
				
			if(isset($this->attributes[$name]))
				return $this->attributes[$name];
				
			return $defValue;
		}
		
		/**
		 * Beállítja az adott attribútumot.
		 * 
		 * FONTOS! Ha a $value null, akkor viszont az lesz, hogy az attribútumot törli. Null értéket ugyanis nem
		 * tárolunk, hiszen minek, hiszen a getAttribute() úgyis null-t ad ha nincs az attribútum (pontosabban a defValue-t,
		 * de ez most mindegy)
		 * 
		 * @param $name
		 * @param mixed $value ha null, akkor az attribútum törölve lesz
		 */
		public function setAttribute($name, $value) {
			
			if(!is_null($value))
			{
				if(is_null($this->attributes))
					$this->attributes = array();
					
				$this->attributes[$name] = $value;
			}
			else
				$this->removeAttribute($name);
		}
		
		
		
		public function removeAttribute($name) {
			
			if(is_null($this->attributes))
				return;
				
			unset($this->attributes, $name);
			if(empty($this->attributes))
				$this->attributes = null;
		}
	}
?>